package org.jeecg.compare.util;


import org.jeecg.compare.enums.ChangeTypeEnum;
import org.jeecg.compare.enums.ModelTypeEnum;
import org.jeecg.compare.model.ChangeModel;
import org.jeecg.compare.model.PropertyModel;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能描述: 比较帮助类 <br/>
 */
public class CompareHelper {

    /**
     * 功能描述: 比较过程（提供给外部使用） <br/>
     */
    public static void compareProcess(List<ChangeModel> changeList, Collection<?> before, Collection<?> after) throws IllegalAccessException, InstantiationException {
        if((before == null || before.isEmpty()) && (after == null || after.isEmpty())) {
            return;
        }
        Map<String, Object> afterObjMap = null, beforeObjMap = null;
        if(before == null || before.isEmpty()) {
            // 全部为新增
            // 转换为Map<String, Object> key:主键值，value:对象信息
            afterObjMap = AnalyzeUtil.toMap(after);
        }
        if(after == null || after.isEmpty()) {
            // 全部为删除
            beforeObjMap = AnalyzeUtil.toMap(before);
        }
        if(before != null && !before.isEmpty() && after != null && !after.isEmpty()) {
            // 修改或者不变
            beforeObjMap = AnalyzeUtil.toMap(before);
            afterObjMap = AnalyzeUtil.toMap(after);
        }
        // 组转成changeModel
        assemblyChangeModelList(changeList, beforeObjMap, afterObjMap);
    }

    /**
     * 功能描述: 组装 <br/>
     *
     * @param changeList 变化列表
     * @param beforeObjMap before
     * @param afterObjMap after
     */
    public static void assemblyChangeModelList(List<ChangeModel> changeList,
                                            Map<String, Object> beforeObjMap,
                                            Map<String, Object> afterObjMap) throws IllegalAccessException, InstantiationException {
        if(beforeObjMap == null) {
            Set<Map.Entry<String, Object>> entries = afterObjMap.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                ChangeModel cm = assemblyChangeModelObj(entry.getValue(), ChangeTypeEnum.ADDED);
                changeList.add(cm);
            }
            return;
        }
        if(afterObjMap == null) {
            Set<Map.Entry<String, Object>> entries = beforeObjMap.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                ChangeModel cm = assemblyChangeModelObj(entry.getValue(), ChangeTypeEnum.REMOVED);
                changeList.add(cm);
            }
            return;
        }
        Set<Map.Entry<String, Object>> beforeEntries = beforeObjMap.entrySet();
        for(Map.Entry<String, Object> beforeEntry : beforeEntries) {
            ChangeModel cm;
            if (!afterObjMap.containsKey(beforeEntry.getKey())) {
                // 如果在after中不存在key，则为删除
                cm = assemblyChangeModelObj(beforeEntry.getValue(), ChangeTypeEnum.REMOVED);
            } else {
                // 继续判断是不变，还是修改
                cm = assemblyChangeModelObj(beforeEntry.getKey(), beforeEntry.getValue(), afterObjMap.get(beforeEntry.getKey()));
            }
            changeList.add(cm);
        }
        // 如果after中有before没有的值，则为新增
        Set<Map.Entry<String, Object>> afterEntries = afterObjMap.entrySet();
        for (Map.Entry<String, Object> afterEntry : afterEntries) {
            if(!beforeObjMap.containsKey(afterEntry.getKey())) {
                ChangeModel cm = assemblyChangeModelObj(afterEntry.getValue(), ChangeTypeEnum.ADDED);
                changeList.add(cm);
            }
        }
    }

    /**
     * 功能描述: 组转对象 <br/>
     *
     * @param key 改变前
     * @param before 改变前
     * @param after 改变后
     * @return "com.compare.model.ChangeModel"
     */
    public static ChangeModel assemblyChangeModelObj(String key, Object before, Object after) throws IllegalAccessException, InstantiationException {
        ChangeModel cm = new ChangeModel();
        // 默认不变
        cm.setChangeType(ChangeTypeEnum.UNCHANGED);
        cm.setModelType(ModelTypeEnum.ENTITY);
        cm.setBefore(before);
        cm.setAfter(after);
        // 设置数据主键
        cm.setTypeValue(key);
        // 设置类名
        cm.setTypeName(before.getClass().getSimpleName());
        cm.setTypeComment(AnalyzeUtil.getPropertyEntity(before));
        // 转换属性
        Map<String, PropertyModel> beforeFiledMap = AnalyzeUtil.toMap(before);
        Map<String, PropertyModel> afterFiledMap = AnalyzeUtil.toMap(after);
        if(beforeFiledMap != null && afterFiledMap != null) {
            // 比较属性是否一致
            List<ChangeModel> children = new ArrayList<>();
            // 同一个对象下面，字段属性肯定一致，缩编去一个key就行
            Set<Map.Entry<String, PropertyModel>> beforeEntries = beforeFiledMap.entrySet();
            for (Map.Entry<String, PropertyModel> beforeEntry : beforeEntries) {
                // 获取属性key
                String propertyKey = beforeEntry.getKey();
                // 通过属性类型，对比两个数据
                ChangeModel child = beforeEntry.getValue().getPte().getProcess().process(beforeEntry.getValue(), afterFiledMap.get(propertyKey));
                children.add(child);
            }
            cm.setChildren(children);
        }
        if(cm.getChildren() != null && !cm.getChildren().isEmpty()) {
            cm.setChangeType(getChildrenChangeType(cm.getChildren()));
        }
        return cm;
    }

    /**
     * 功能描述: 获取子属性的最终变化类型 <br/>
     *
     * @param children 子变化模型
     * @return "com.compare.enums.ChangeTypeEnum"
     */
    public static ChangeTypeEnum getChildrenChangeType(List<ChangeModel> children) {
        // 获取children中是否全部为的变化类型
        List<ChangeTypeEnum> changeTypes = children.stream().map(ChangeModel::getChangeType).distinct().collect(Collectors.toList());
        if(changeTypes.size() == 1 && ChangeTypeEnum.UNCHANGED.equals(changeTypes.get(0))) {
            return ChangeTypeEnum.UNCHANGED;
        } else {
            return ChangeTypeEnum.MODIFIED;
        }
    }

    /**
      * 功能描述: 组装单个对象 <br/>
      *
      * @param obj 对象
      * @param cte 变化类型
      * @return "com.compare.model.ChangeModel"
      */
    public static ChangeModel assemblyChangeModelObj(Object obj, ChangeTypeEnum cte) throws IllegalAccessException, InstantiationException {
        ChangeModel cm = new ChangeModel();
        // 设置变化类型
        cm.setChangeType(cte);
        cm.setModelType(ModelTypeEnum.ENTITY);
        // 删除的，说明before有，after没有
        cm.setBefore(ChangeTypeEnum.REMOVED.equals(cte) ? obj : null);
        // 新增的，说明after有，before没有
        cm.setAfter(ChangeTypeEnum.ADDED.equals(cte) ? obj : null);
        // 设置数据主键
        cm.setTypeValue(AnalyzeUtil.getKey(obj));
        // 设置类名
        cm.setTypeName(obj.getClass().getSimpleName());
        cm.setTypeComment(AnalyzeUtil.getPropertyEntity(obj));
        // 转换属性
        Map<String, PropertyModel> filedMap = AnalyzeUtil.toMap(obj);
        if(filedMap != null) {
            List<ChangeModel> children = new ArrayList<>();
            Set<Map.Entry<String, PropertyModel>> entries = filedMap.entrySet();
            for (Map.Entry<String, PropertyModel> entry : entries) {
                // 拼接字段
                ChangeModel cmc = entry.getValue().getPte().getProcess().process(entry.getValue(), cte);
                if(cmc != null) {
                    children.add(cmc);
                }
            }
            cm.setChildren(children);
        }
        return cm;
    }

}
